<?php
/**
 *  serialize 和 unserialize 用于缓存处理
 */
class DnModelBase {
	const TABLE_SPLIT_NONE = 0;
	const TABLE_SPLIT_DIV = 1;
	const TABLE_SPLIT_MOD = 2;

	public $id;
	public $table_prikey = 'id';
	public $data = array();
	
	
	public $is_inited = false;
	public $cache='DnCache';
	
	//选项目培植
	public $config=array(
		'table_name'	=>'',
		'table_prikey'	=>'id',
		'no_cache'		=>true,
		'to_create'		=>false,
		'split_mode'	=>0,
	);
	
	protected $auto_to_create=false;
	protected $table_split = 0;
	protected $table_split_mode = self :: TABLE_SPLIT_NONE;
	protected $table_mode = 0;
	protected $table_name = '';
	protected $real_table_name = '';
	

	public function __construct($id = 0, $config = array()) {
		$this->id = $id;
		$this->config = array_merge($this->config,$config);
		$this->table_name=$this->config['table_name'];
		$this->table_prikey=$this->config['table_prikey'];
		$this->real_table_name = $this->getRealTableName();
		if($this->auto_to_create && !$this->id && !isset($this->config['to_create'])){
			$this->config['to_create']=true;
		}
		if (!empty($this->config['to_create'])){
			return;
		}
		if(empty($id)){return;}
		$this->init($id, $config);
		$this->is_inited = true;
	}
	protected function init($id) {
		if (empty($this->config['no_cache'])) {
			$this->data = $this->getDataByCache();
			if(false===$this->data){
				$this->data = $this->getDataByDataBase();
				$this->setDataToCache($this->data);
			}
		}else{
			$this->data = $this->getDataByDataBase();
		}
		//$this->init_data =is_object($this->data)?clone $this->data:$this->data;
	}
	
	protected function getCacheKey() {
		return  'Dn' . $this->table_name . "_" . $this->id;
	}
	protected function calcData($data)
	{
		return $data;
	}
	protected function getDataByCache() {
		$ret = call_user_func(array($this->cache,'Get'),$this->getCacheKey());
		if (FALSE === $ret){return array();}
		$data=$this->calcData($data);
		return $data;
	}
	protected function setDataToCache($data) {
		if(empty($data)){return;}
		$ret = call_user_func(array($this->cache,'Set'),$this->getCacheKey(),$data);
	}
	protected function getRealTableName() {
		switch ($this->config['split_mode']) {
			case self :: TABLE_SPLIT_DIV :
				$ret = $this->table_name . '_' . floor($id / $this->table_split);
				break;
			case self :: TABLE_SPLIT_MOD :
				$ret = $this->table_name . '_' . floor($id % $this->table_split);
				break;
			case self :: TABLE_SPLIT_NONE :
			default;
				$ret = $this->table_name;
				break;
		}
		$ret=empty($this->config['table_prefix'])?$ret:$this->config['table_prefix'].$ret;
		return $ret;
	}
	protected function getDataByDatabase() {
		$data = $this->_selectData($this->real_table_name, $this->id, $this->table_prikey,1);
		
		$data=$this->calcData($data);
		return $data;
	}
	protected function setDataToDataBase($data) {
		$data_to_save=$data;
		foreach($data as $k => $v){
			if(!is_scalar($v)){
				unset($data_to_save[$k]);
			}
		}
	
		$flag=$this->_updateData($data_to_save, $this->real_table_name, $this->id, $this->table_prikey);
		
		return $flag;
	}
	protected function _selectData($table_name, $id, $prikey, $limit = false, $page = -1,$use_calc_rows=false) {
		$limitstr = '';
		if ($limit) {
			if ($page >= 0) {
				$limitstr = "LIMIT $limit,$page";
			} else {
				$limitstr = "LIMIT $limit";
			}
		}
		$calc_rows=($use_calc_rows)?'SQL_CALC_FOUND_ROWS ':'';//FOUND_ROWS() //TODO
		$sql = "SELECT $calc_rows * FROM `$table_name` WHERE $prikey=? $limitstr";
		$data = DnDB :: GO($sql, $id);
		return $data;
	}
	protected function _getLastSelectCount()
	{
		$sql="SELECT FOUND_ROWS() AS found LIMIT 1";
		$ret=DnDB::GO($sql);
		return $ret;
	}
	protected function _getLastInsertId()
	{
		$sql="SELECT LAST_INSERT_ID() AS found LIMIT 1";
		$ret=DnDB::GO($sql);
		return $ret;
	}
	protected function _updateData($data, $table_name, $id, $prikey,$limit=0) {
		if(isset($data[$prikey])){unset($data[$prikey]);}
		$sql = "UPDATE $table_name SET ".DnDB::A2U($data)." WHERE $prikey=".DnDB::E($id).(($limit>0)?" LIMIT $limit":'');
		$ret=DnDB::GO($sql);
		return $ret;
	}
	protected function _replaceData($data, $table_name, $id, $prikey) {
		$data[$prikey]=$id;
		$sql = "REPLACE INTO $table_name SET ".DnDB::A2U($data).", $prikey=".DnDB::E($id);
		$ret=DnDB::GO($sql);
		return $ret;
	}
	protected function _insertData($data, $table_name, $id, $prikey) {
		$data[$prikey]=$id;
		$sql = "INSERT INTO `$table_name`  ".DnDB::A2I($data);
		$ret=DnDB::GO($sql);
		return $ret;
	}
	protected function _deleteData($data,$table_name,$id,$prikey,$limit=1)
	{
		$sql="DELETE FROM `$table_name` WHERE $prikey=".DnDB::E($id).(($limit>=0)?" LIMIT $limit":'LIMIT 1');
		$ret=DnDB::GO($sql);
	}
	///////////////////////////////////////////////////////////////////////////
	public function initDataByGiven($data) 
	{
		if(empty($data)){return $data;}
		$this->id=$data[$this->table_prikey];
		
		$this->data=$data;
		$this->setDataToCache($data);
		$this->is_inited=true;
		return $data;
	}
	protected function cleanCache($ignore = null) {
		call_user_func(array($this->cache ,'Delete'),$this->getCacheKey());
	}
	public function save()
	{
		if (!empty($this->config['no_cache'])) {
			$this->setDataToCache($this->data);
		}
		$this->setDataToDataBase($this->data);
		
	}
	
	public function create($data=array()) {
		$data_to_save=$data;
		foreach($data as $k => $v){
			if(!is_scalar($v)){
				unset($data_to_save[$k]);
			}
		}
	
		$id=$this->_insertData($data_to_save, $this->real_table_name, $this->id, $this->table_prikey);
		if($id){
			$data[$this->table_prikey]=$id;
			$this->id=$id;
			$this->data=$data;
			$this->setDataToCache($data);
		}
		return $id;
	}
	public function update($data)
	{
		$this->data=array_merge($this->data,$data);
		$this->data[$this->table_prikey]=$this->id;
		$this->calcData($this->data);
		$this->save();
	}
	public function delete()
	{
		$ret=$this->_deleteData($this->data, $this->real_table_name, $this->id, $this->table_prikey);
		
		if(!$ret){return false;}
		$this->cleanCache();
		return true;
		
	}
	public function getData()
	{
		return $this->data;
	}
}